package nx.simple3d.data;

/**
 * Represents a single, renderable mesh. 
 * @author simon
 *
 */
public class Mesh extends TriangleHandler{
  private GeometryProvider geometryProvider;
  private int verticesCount = -1;
  private int triangleCount = -1;
  private Matrix transformation;
  private Matrix transformedProjection;
  
  private int readableVectorsSection = 1; 
  public static enum VECTOR_SECTIONS{
    ORIGINAL, 
    READABLE, 
    WRITEABLE
  };

  /**
   * Constructs a mesh. This reqiuires a geometry provider as parameter
   * which will be moved to the given vector base on the compile call.
   * @param vb The underlying vector base
   * @param geometryProvider The geometry provider which provides the mesh-geometry
   */
  public Mesh(GeometryProvider geometryProvider) {
    super();
    this.geometryProvider = geometryProvider;
  }

  @Override
  public int getRequiredVectorCacheSize() {
    return getVerticesCount() * 3;
  }

  @Override
  public int getRequiredTriangleCacheSize() {
    return getTriangleCount();
  }
  
  public Matrix getTransformation(){
    if(transformation == null){
      transformation = new Matrix();
      transformedProjection = new Matrix();
    }
    return transformation;
  }
  
  public Matrix getProjectedTransformation(Matrix projection){
    if(transformation != null){
      return projection.applyOn(transformedProjection, transformation);
    }
    else{
      return projection;
    }
  }
  
  public int getVerticesCount(){
    if(verticesCount == -1){
      verticesCount = geometryProvider.getVertices().length / 3;
    }
    return verticesCount;
  }
  
  public int getTriangleCount(){
    if(triangleCount == -1){
      triangleCount = geometryProvider.getIndicesVertices().length / 3;
    }
    return triangleCount;
  }


  @Override
  public void initializeTriangleData() {
    int[] trianglesIndices = geometryProvider.getIndicesVertices();
    for(int i = 0; i < trianglesIndices.length / 3; i++){
      tb.setTriangle(
          i + tbOffset,
          trianglesIndices[i * 3 + 0],
          trianglesIndices[i * 3 + 1],
          trianglesIndices[i * 3 + 2]);
    } 
  }
  
  @Override
  public void initializeVectorData() {
    double[] vertices = geometryProvider.getVertices();
    for(int i = 0; i < vertices.length / 3; i++){
      vb.setVector(
          i + vbOffset,
          vertices[i * 3 + 0],
          vertices[i * 3 + 1],
          vertices[i * 3 + 2]);
    }
  }
  
  public int getOffsetToVectorSection(VECTOR_SECTIONS requestedSection){
    switch(requestedSection){
    case ORIGINAL:
      return vbOffset;
    case READABLE:
      return vbOffset + getVerticesCount() * readableVectorsSection;
    case WRITEABLE:
      return vbOffset + getVerticesCount() * (3 - readableVectorsSection);
    }
    return -1;
  }
  
  public void writingCompleted(){
    readableVectorsSection = 3 - readableVectorsSection;
  }
}
